/**
 * Symbol
 */

// /********** cache.js **********/
// const cache = []
// const cache2 = []

// /********** a.js **********/
// // 假设在a.js中设置了 cache的键为'foo'
// cache['foo'] = Math.random()
// // 为了避免冲突，会使用约定的形式，比如在a.js文件中使用a_开头的遍历
// cache2['a_foo'] = Math.random()

// /********** b.js **********/
// // 在b.js中也设置了 cache的键为'foo'
// cache['foo'] = 123
// // 为了避免冲突，会使用约定的形式，比如在b.js文件中使用b_开头的遍历
// cache2['b_foo'] = 456

// // 此时会出现冲突的情况
// console.log(cache) // [ foo: 123 ]
// console.log(cache2) // [ a_foo: 0.2730646218020336, b_foo: 456 ]


// // symbol
// const s = Symbol()
// console.log(s) // Symbol()
// console.log(typeof s) // symbol
// console.log(Symbol() === Symbol()) // false

// console.log(Symbol('foo')) // Symbol(foo)
// console.log(Symbol('foo')) // Symbol(foo)
// console.log(Symbol('bar')) // Symbol(bar)

// // 可作为对象的键
// const obj = {}
// obj[Symbol()] = 123
// obj[Symbol()] = 456
// console.log(obj) // { [Symbol()]: 123, [Symbol()]: 456 }

// // 也可使用计算属性名的方式，在对象字面量上使用
// const obj2 = {
//   [Symbol()]: 789
// }
// console.log(obj2) // { [Symbol()]: 789 }


// // 模拟对象私有成员
// /********** a.js **********/
// const name = Symbol()
// const person = {
//   [name]: 'zhangsan',
//   say() {
//     console.log(this[name])
//   }
// }

// /********** a.js **********/
// // 在外部文件，由于无法创建一个完全相同的 Symbol，因此无法直接访问到成员
// // person[Symbol()]
// // 只能访问对象中的普通成员，由此实现了私有成员
// person.say()


/**
 * symbol 补充
 */
console.log(Symbol('foo') === Symbol('foo')) // false

// 若要在全局使用 symbol，可使用.for 方法
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1 === s2) // true

console.log(Symbol.for(true) === Symbol.for('true')) // true

// 内部 symbol 常量，做为内部方法的标识，用来让自定义对象实现 js 对象内置的接口
console.log(Symbol.iterator) // Symbol(Symbol.iterator)
console.log(Symbol.hasInstance) // Symbol(Symbol.hasInstance)

// 如 Symbol.toStringTag
const obj = {}
// [object Object] 被称为对象的 toString() 标签
console.log(obj.toString()) // [object Object]
// 若想自定义成员的toString()标签，可在对象中增加一个特定的成员进行标识

// toStringTag: 内置 symbol 
const obj2 = {
  [Symbol.toStringTag]: 'XObject'
}
console.log(obj2.toString()) // [object XObject]

// 
const obj3 = {
  [Symbol()]: 'symbol value',
  'foo': 'normal value'
}
console.log(Object.keys(obj3)) // [ 'foo' ]
console.log(JSON.stringify(obj3)) // {"foo":"normal value"}
console.log(Object.getOwnPropertySymbols(obj3)) // [ Symbol() ]